package puzzle.nurikabe.solver;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import puzzle.common.point.Direction;
import puzzle.common.point.Pnt;
import puzzle.common.solver.AbstractTopology;
import puzzle.nurikabe.data.NurikabeBoard;
import puzzle.nurikabe.data.StateUtil;
import tomoto.assertion.AssertUtil;
import tomoto.util.CollectionUtil;

public class NurikabeTopology extends AbstractTopology {
	private Map<Integer, List<Pnt>> m_shimaEscapePoints;
	private Map<Integer, List<Pnt>> m_kabeEscapePoints;
	private int m_fixedArea;
	private int m_undecidedArea;
//	private int[] m_closureNumbers;
//	private Map<Integer, IntHolder> m_closureAreaMap;

	public NurikabeTopology(NurikabeBoard b) {
		m_shimaEscapePoints = new HashMap<Integer, List<Pnt>>();
		m_kabeEscapePoints = new HashMap<Integer, List<Pnt>>();

		analyzeEscapePoints(b);
//		analyzeClosure(b);

	}

	private void analyzeEscapePoints(NurikabeBoard b) {
		for (int y = 0; y < b.height; y++) {
			for (int x = 0; x < b.width; x++) {
				int n = b.getBoardState(x, y);

				if (n > 0) {
					registerEscapePointsAround(b, m_shimaEscapePoints, n, x, y);
					m_fixedArea++;
				} else if (n < 0) {
					registerEscapePointsAround(b, m_kabeEscapePoints, -n, x, y);
					m_fixedArea++;
				} else {
					m_undecidedArea++;
				}
			}
		}
	}

	private void registerEscapePointsAround(NurikabeBoard b, Map<Integer, List<Pnt>> escapePoints,
			int n, int x, int y) {
		List<Pnt> ps = escapePoints.get(n);
		if (ps == null) {
			ps = new ArrayList<Pnt>();
			escapePoints.put(n, ps);
		}

		for (Direction d : Direction.CLOCKWISE4) {
			int x1 = x + d.v.dx;
			int y1 = y + d.v.dy;
			int n1 = b.getBoardState(x1, y1);
			if (n1 == 0) {
				CollectionUtil.addOnce(ps, new Pnt(x1, y1));
			} else {
				int n0 = b.getBoardState(x, y);
				if ((n1 > 0) ^ (n0 > 0) || n1 == n0 || n1 == StateUtil.OUT_OF_BOARD) {
					// OK
				} else {
					throw AssertUtil.fail();
				}
			}
		}
	}

//	private void analyzeClosure(final NurikabeBoard b) {
//		ClosureAnalyzable g = new ClosureAnalyzable() {
//			public int getHeight() {
//				return b.height;
//			}
//
//			public int getWidth() {
//				return b.width;
//			}
//
//			public boolean isClosureMember(int x, int y) {
//				int n = b.getBoardState(x, y);
//				return n == 0 || StateUtil.isUndeterminedShima(n);
//			}
//
//			public boolean isConnected(int x, int y, Direction d) {
//				return isClosureMember(x + d.v.dx, y + d.v.dy);
//			}
//		};
//
//		ClosureAnalyzer z = new ClosureAnalyzer(g, ClosureAnalyzer.Type.EIGHT_DIR);
//		m_closureNumbers = z.getClosureNumbers();
//
//		m_closureAreaMap = new HashMap<Integer, IntHolder>();
//		for (int i = 0; i < m_closureNumbers.length; i++) {
//			IntHolder area = m_closureAreaMap.get(i);
//			if (area == null) {
//				area = new IntHolder();
//				m_closureAreaMap.put(i, area);
//			}
//			area.value++;
//		}
//	}

	public Map<Integer, List<Pnt>> getShimaEscapePoints() {
		return m_shimaEscapePoints;
	}

	public Map<Integer, List<Pnt>> getKabeEscapePoints() {
		return m_kabeEscapePoints;
	}

	public int getFixedArea() {
		return m_fixedArea;
	}

	public int getUndecidedArea() {
		return m_undecidedArea;
	}

//	public int[] getClosureNumbers() {
//		return m_closureNumbers;
//	}
//
//	public int getClosureArea(int n) {
//		return m_closureAreaMap.containsKey(n) ? m_closureAreaMap.get(n).value : 0;
//	}

}
